using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace TXLooker.Hooks
{
    [ToolboxBitmap(typeof(LLKeyboardHook), "keyboard.png"), Description("Component that hooks the keyboard system wide."), DefaultEvent("StateChanged")]
    public class LLKeyboardHook : Component
    {
        [MarshalAs(UnmanagedType.FunctionPtr)]
        private Win32.WKCallBack _keyboardProc;
        private Keys _keyData;
        private static IntPtr hKeyboardHook;

        public event KeyEventHandler KeyDown;

        public event KeyEventHandler KeyUp;

        public event StateEventHandler StateChanged;

        [DebuggerHidden]
        protected override void Dispose(bool disposing)
        {
            this.RemoveHook(false);
            base.Dispose(disposing);
        }

        [DebuggerHidden]
        public bool InstallHook([Optional, DefaultParameterValue(true)] bool ThrowEx)
        {
            if (hKeyboardHook == IntPtr.Zero)
            {
                this._keyboardProc = new Win32.WKCallBack(this.LLKeyboardProc);
                IntPtr hINSTANCE = Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]);
                hKeyboardHook = Win32.SetWindowsHookEx(13, this._keyboardProc, hINSTANCE, 0);
                if (hKeyboardHook == IntPtr.Zero)
                {
                    if (ThrowEx)
                    {
                        throw new Win32Exception();
                    }
                    return false;
                }
                this.OnStateChanged(new StateChangedEventArgs(this.State, IntPtr.Zero));
            }
            return true;
        }

        [DebuggerHidden]
        private int LLKeyboardProc(int nCode, uint wParam, ref Win32.KBDLLHOOKSTRUCT lParam)
        {
            if (nCode >= 0)
            {
                KeyEventArgs args;
                Keys vkCode = (Keys)((int)lParam.vkCode);
                bool flag = true;
                if (flag == ((wParam == 0x100L) | (wParam == 260L)))
                {
                    if ((vkCode == Keys.LMenu) | (vkCode == Keys.RMenu))
                    {
                        this._keyData |= Keys.Alt;
                        args = new TXLooker.Hooks.KeyEventArgs(this._keyData | Keys.Menu, vkCode);
                    }
                    else if ((vkCode == Keys.LControlKey) | (vkCode == Keys.RControlKey))
                    {
                        this._keyData |= Keys.Control;
                        args = new TXLooker.Hooks.KeyEventArgs(this._keyData | Keys.ControlKey, vkCode);
                    }
                    else if ((vkCode == Keys.LShiftKey) | (vkCode == Keys.RShiftKey))
                    {
                        this._keyData |= Keys.Shift;
                        args = new TXLooker.Hooks.KeyEventArgs(this._keyData | Keys.ShiftKey, vkCode);
                    }
                    else
                    {
                        args = new TXLooker.Hooks.KeyEventArgs(this._keyData | vkCode, vkCode);
                    }
                    this.OnKeyDown(args);
                    if (args.Handled)
                    {
                        return 1;
                    }
                }
                else if (flag == ((wParam == 0x101L) | (wParam == 0x105L)))
                {
                    if ((vkCode == Keys.LMenu) | (vkCode == Keys.RMenu))
                    {
                        this._keyData &= ~Keys.Alt;
                        args = new TXLooker.Hooks.KeyEventArgs(this._keyData | Keys.Menu, vkCode);
                    }
                    else if ((vkCode == Keys.LControlKey) | (vkCode == Keys.RControlKey))
                    {
                        this._keyData &= ~Keys.Control;
                        args = new TXLooker.Hooks.KeyEventArgs(this._keyData | Keys.ControlKey, vkCode);
                    }
                    else if ((vkCode == Keys.LShiftKey) | (vkCode == Keys.RShiftKey))
                    {
                        this._keyData &= ~Keys.Shift;
                        args = new TXLooker.Hooks.KeyEventArgs(this._keyData | Keys.ShiftKey, vkCode);
                    }
                    else
                    {
                        args = new TXLooker.Hooks.KeyEventArgs(this._keyData | vkCode, vkCode);
                    }
                    this.OnKeyUp(args);
                    if (args.Handled)
                    {
                        return 1;
                    }
                }
            }
            return Win32.CallNextHookEx(hKeyboardHook, nCode, wParam, ref lParam);
        }

        [DebuggerHidden]
        protected virtual void OnKeyDown(KeyEventArgs e)
        {
            KeyEventHandler keyDownEvent = this.KeyDown;
            if (keyDownEvent != null)
            {
                keyDownEvent(this, e);
            }
        }

        [DebuggerHidden]
        protected virtual void OnKeyUp(KeyEventArgs e)
        {
            KeyEventHandler keyUpEvent = this.KeyUp;
            if (keyUpEvent != null)
            {
                keyUpEvent(this, e);
            }
        }

        [DebuggerHidden]
        protected virtual void OnStateChanged(StateChangedEventArgs e)
        {
            StateEventHandler stateChangedEvent = this.StateChanged;
            if (stateChangedEvent != null)
            {
                stateChangedEvent(this, e);
            }
        }

        [DebuggerHidden]
        public bool RemoveHook([Optional, DefaultParameterValue(true)] bool ThrowEx)
        {
            this._keyboardProc = null;
            this._keyData = Keys.None;
            if (hKeyboardHook != IntPtr.Zero)
            {
                if (!Win32.UnhookWindowsHookEx(hKeyboardHook))
                {
                    hKeyboardHook = IntPtr.Zero;
                    if (ThrowEx)
                    {
                        throw new Win32Exception();
                    }
                    return false;
                }
                hKeyboardHook = IntPtr.Zero;
                this.OnStateChanged(new StateChangedEventArgs(this.State, IntPtr.Zero));
            }
            return true;
        }

        [Browsable(false)]
        public bool AltKeyDown
        {
            [DebuggerHidden]
            get
            {
                return ((this._keyData & Keys.Alt) != Keys.None);
            }
        }

        public static System.Reflection.Assembly Assembly
        {
            [DebuggerHidden]
            get
            {
                return System.Reflection.Assembly.GetExecutingAssembly();
            }
        }

        public static string Author
        {
            [DebuggerHidden]
            get
            {
                return "Arman Ghazanchyan";
            }
        }

        [Browsable(false)]
        public bool CtrlKeyDown
        {
            [DebuggerHidden]
            get
            {
                return ((this._keyData & Keys.Control) != Keys.None);
            }
        }

        [Browsable(false)]
        public bool ShiftKeyDown
        {
            [DebuggerHidden]
            get
            {
                return ((this._keyData & Keys.Shift) != Keys.None);
            }
        }

        [Browsable(false)]
        public HookState State
        {
            [DebuggerHidden]
            get
            {
                if (hKeyboardHook == IntPtr.Zero)
                {
                    return HookState.Uninstalled;
                }
                return HookState.Installed;
            }
        }

        public static System.Version Version
        {
            [DebuggerHidden]
            get
            {
                return Assembly.GetName().Version;
            }
        }

        public delegate void KeyEventHandler(object sender, KeyEventArgs e);

        public delegate void StateEventHandler(object sender, StateChangedEventArgs e);
    }
}
